package com.thiswhyme.elasticsearch.config;

import com.thiswhyme.elasticsearch.core.BaseDocumentClient;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * @description: es配置
 * @author: thiswhyme
 * @date: 2021/10/14
 */
@Configuration
@EnableConfigurationProperties(ElasticSearchProperties.class)
@ConditionalOnProperty(name = "thiswhyme.elasticsearch.enable", havingValue = "true")
public class ElasticSearchAutoConfiguration {

    @Bean
    @Primary
    public RestHighLevelClient restHighLevelClient(ElasticSearchProperties properties) {
        // 解析地址
        String clusterAddress = properties.getClusterAddress();
        List<HttpHost> hostList = new ArrayList<>();
        if (null != clusterAddress && clusterAddress.trim().length() > 0) {
            String[] hosts = clusterAddress.split(",");
            for (String host : hosts) {
                String[] address = host.split(":");
                hostList.add(new HttpHost(address[0], Integer.parseInt(address[1])));
            }
        } else {
            HttpHost httpHost = new HttpHost(properties.getHost(), properties.getPort());
            hostList.add(httpHost);
        }

        // 连接配置
        RestClientBuilder builder = RestClient.builder(hostList.toArray(new HttpHost[0]))
                .setRequestConfigCallback(requestConfigBuilder -> {
                    Optional.ofNullable(properties.getConnectTimeout()).ifPresent(requestConfigBuilder::setConnectTimeout);
                    Optional.ofNullable(properties.getSocketTimeout()).ifPresent(requestConfigBuilder::setSocketTimeout);
                    Optional.ofNullable(properties.getConnectionRequestTimeOut()).ifPresent(requestConfigBuilder::setConnectionRequestTimeout);
                    return requestConfigBuilder;
                })
                .setHttpClientConfigCallback(httpClientBuilder -> {
                    Optional.ofNullable(properties.getMaxConnTotal()).ifPresent(httpClientBuilder::setMaxConnTotal);
                    Optional.ofNullable(properties.getMaxConnPerRoute()).ifPresent(httpClientBuilder::setMaxConnPerRoute);
                    Optional.ofNullable(properties.getKeepAliveTime()).ifPresent(time -> {
                        httpClientBuilder.setKeepAliveStrategy(((httpResponse, httpContext) -> time));
                    });
                    return httpClientBuilder;
                });

        // 鉴权配置
        ElasticSearchProperties.AuthConfig authConfig = properties.getAuth();
        if (null != authConfig && authConfig.getEnable()) {
            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
            credentialsProvider.setCredentials(AuthScope.ANY,
                    new UsernamePasswordCredentials(authConfig.getUserName(), authConfig.getPassword()));
            builder.setHttpClientConfigCallback(httpClientBuilder -> {
                httpClientBuilder.disableAuthCaching().setDefaultCredentialsProvider(credentialsProvider);
                return httpClientBuilder;
            });
        }

        // 连接池配置
        return new RestHighLevelClient(builder);
    }

    @Bean
    @ConditionalOnMissingBean(BaseDocumentClient.class)
    public BaseDocumentClient baseDocumentClient(RestHighLevelClient restHighLevelClient) {
        return new BaseDocumentClient(restHighLevelClient);
    }
}
